<?php
/**
*
* @package shopBB
* @copyright (c) 2008 EXreaction, Lithium Studios
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*
*/

class acp_shop
{
	var $u_action;
	var $new_config = array();
	var $parent_id = 0;

	function main($id, $mode)
	{
		global $phpbb_root_path, $phpEx, $user;

		if (!defined('PHPBB_ROOT_PATH')) define('PHPBB_ROOT_PATH', $phpbb_root_path);
		if (!defined('SHOPBB_PATH')) define('SHOPBB_PATH', PHPBB_ROOT_PATH . 'shop/');
		if (!defined('PHP_EXT')) define('PHP_EXT', $phpEx);

		include(SHOPBB_PATH . 'constants.' . PHP_EXT);
		include(SHOPBB_PATH . 'shop_class.' . PHP_EXT);
		include(SHOPBB_PATH . 'functions.' . PHP_EXT);
		include(SHOPBB_PATH . 'plugins/plugins.' . PHP_EXT);

		new shop();
		new shop_plugins();

		$submit = (isset($_POST['submit'])) ? true : false;

		// Check Form Key
		add_form_key('acp_shop');
		if ($submit && !check_form_key('acp_shop'))
		{
			trigger_error($user->lang['FORM_INVALID'] . adm_back_link($this->u_action), E_USER_WARNING);
		}

		$user->add_lang(array('mods/shop/shop', 'acp/shop'));

		switch($mode)
		{
			case 'plugins' :
				$this->plugins($id, $mode);
			break;
			case 'categories' :
				$this->categories($id, $mode);
			break;
			default :
				$default = true;
				extract(shop_plugins::plugin_do('acp_default', compact('default', 'id', 'mode'))); // make sure to set default to false if you use your own page

				if ($default)
				{
					$this->settings($id, $mode);
				}
		}

		shop_plugins::plugin_do('acp_end');
	}

	function settings($id, $mode)
	{
		global $config, $db, $user, $auth, $template;

		$submit = (isset($_POST['submit'])) ? true : false;
		$action = request_var('action', '');

		$this->tpl_name = 'acp_board';
		$this->page_title = $user->lang['ACP_SHOP'];

		shop_plugins::plugin_do('acp_main_start');

		$settings = array(
			'legend0'					=> 'SHOP_VERSION',
			'shopbb_version'			=> array('lang' => 'SHOP_VERSION',			'type' => 'custom',		'method' => 'shopbb_version',			'explain' => false),

			'legend1'					=> 'SHOP_SETTINGS',
			'shop_enabled'				=> array('lang' => 'ENABLE_SHOP',			'validate' => 'bool',	'type' => 'radio:enabled_disabled',		'explain' => true),
			'shop_seo'					=> array('lang' => 'SHOP_SEO',				'validate' => 'bool',	'type' => 'radio:enabled_disabled',		'explain' => true),

			'legend2'					=> 'CURRENCY_SETTINGS',
			'shop_currency'				=> array('lang' => 'SHOP_CURRENCY',			'type' => 'custom',		'method' => 'shop_currency',			'explain' => true),
			'shop_buy_currency'			=> array('lang' => 'SHOP_BUY_CURRENCY',		'validate' => 'bool',	'type' => 'radio:enabled_disabled',		'explain' => true),
			'shop_sell_currency'		=> array('lang' => 'SHOP_SELL_CURRENCY',	'validate' => 'bool',	'type' => 'radio:enabled_disabled',		'explain' => true),
		);

		shop_plugins::plugin_do_ref('acp_main_settings', $settings);

		$this->new_config = $config;
		$cfg_array = (isset($_REQUEST['config'])) ? utf8_normalize_nfc(request_var('config', array('' => ''), true)) : $this->new_config;
		$error = array();

		// We validate the complete config if whished
		validate_config_vars($settings, $cfg_array, $error);

		// Do not write values if there is an error
		if (sizeof($error))
		{
			$submit = false;
		}

		$template->assign_vars(array(
			'L_TITLE'			=> $user->lang['SHOP_SETTINGS'],
			'L_TITLE_EXPLAIN'	=> $user->lang['SHOP_SETTINGS_EXPLAIN'],

			'S_ERROR'			=> (sizeof($error)) ? true : false,
			'ERROR_MSG'			=> implode('<br />', $error),

			'U_ACTION'			=> $this->u_action,
		));

		foreach ($settings as $config_key => $vars)
		{
			if ($submit)
			{
				if (!isset($cfg_array[$config_key]) || strpos($config_key, 'legend') !== false)
				{
					continue;
				}

				$this->new_config[$config_key] = $config_value = $cfg_array[$config_key];

				set_config($config_key, $config_value);
			}
			else
			{
				if (!is_array($vars) && strpos($config_key, 'legend') === false)
				{
					continue;
				}

				if (strpos($config_key, 'legend') !== false)
				{
					$template->assign_block_vars('options', array(
						'S_LEGEND'		=> true,
						'LEGEND'		=> (isset($user->lang[$vars])) ? $user->lang[$vars] : $vars)
					);

					continue;
				}

				$type = explode(':', $vars['type']);

				$l_explain = '';
				if ($vars['explain'] && isset($vars['lang_explain']))
				{
					$l_explain = (isset($user->lang[$vars['lang_explain']])) ? $user->lang[$vars['lang_explain']] : $vars['lang_explain'];
				}
				else if ($vars['explain'])
				{
					$l_explain = (isset($user->lang[$vars['lang'] . '_EXPLAIN'])) ? $user->lang[$vars['lang'] . '_EXPLAIN'] : '';
				}

				$template->assign_block_vars('options', array(
					'KEY'			=> $config_key,
					'TITLE'			=> (isset($user->lang[$vars['lang']])) ? $user->lang[$vars['lang']] : $vars['lang'],
					'S_EXPLAIN'		=> $vars['explain'],
					'TITLE_EXPLAIN'	=> $l_explain,
					'CONTENT'		=> build_cfg_template($type, $config_key, $this->new_config, $config_key, $vars),
					)
				);
			}
		}

		if ($submit)
		{
			add_log('admin', 'LOG_SHOP_CONFIG');

			trigger_error($user->lang['CONFIG_UPDATED'] . adm_back_link($this->u_action));
		}
	}

	function shopbb_version($value, $key)
	{
		global $user, $config, $cache;

		$version = $user->lang['DATABASE_VERSION'] . ': ' . $value . '<br />';
		$version .= $user->lang['LATEST_VERSION'] . ': ';

		$latest_version = $cache->get('shopbb_version');
		if ($latest_version === false)
		{
			if (!function_exists('get_remote_file'))
			{
				include(PHPBB_ROOT_PATH . 'includes/functions_admin.' . PHP_EXT);
			}

			$errstr = $errno = '';
			$latest_version = get_remote_file('lithiumstudios.org', '/updatecheck', 'shopbb.txt', $errstr, $errno);

			$cache->put('shopbb_version', $latest_version, 3600);
		}

		if ($latest_version === false)
		{
			$version .= $user->lang['NOT_AVAILABLE'];
			$version .= '<br />' . sprintf($user->lang['CLICK_CHECK_NEW_VERSION'], '<a href="http://www.lithiumstudios.org/forum/viewtopic.php?f=41&t=433">', '</a>');
		}
		else
		{
			$version .= $latest_version;
			if (version_compare($file_version, $latest_version, '<'))
			{
				$version .= '<br />' . sprintf($user->lang['CLICK_GET_NEW_VERSION'], '<a href="http://www.lithiumstudios.org/forum/viewtopic.php?f=41&t=433">', '</a>');
			}
		}

		return $version;
	}

	function shop_currency($value, $key)
	{
		$select = "<select name=\"{$key}\" id=\"{$key}\">";

	    $dh = @opendir(SHOPBB_PATH . 'currency/');
		if ($dh)
		{
			while (($file = readdir($dh)) !== false)
			{
				if (strpos($file, PHP_EXT) !== false)
				{
					include(SHOPBB_PATH . 'currency/' . $file);

					$class = substr($file, 0, -(strlen(PHP_EXT) + 1));
					$currency = new $class;
					if ($currency->is_installed())
					{
						$select .= "<option value=\"{$class}{$option}\">" . $option_name . '</option>';
					}
				}
			}
			closedir($dh);
		}
		$select .= '</select>';
		return $select;
	}

	// Code taken from acp_category
	function categories($id, $mode)
	{
		global $db, $user, $auth, $template, $cache, $config;

		$this->tpl_name = 'acp_shop_categories';
		$this->page_title = 'ACP_SHOP_CATEGORIES';

		$action		= request_var('action', '');
		$update		= (isset($_POST['update'])) ? true : false;
		$cat_id	= request_var('c', 0);

		$this->parent_id	= request_var('parent_id', 0);
		$category_data = $errors = array();

		// Clear the categories cache
		$cache->destroy('_shop_cats');

		// Major routines
		if ($update)
		{
			switch ($action)
			{
				case 'delete':
					$action_subcategories = request_var('action_subcategories', '');
					$subcategories_to_id = request_var('subcategories_to_id', 0);
					$action_items = request_var('action_items', '');
					$items_to_id = request_var('items_to_id', 0);
					$row = $this->get_category_info($cat_id);

					$errors = $this->delete_category($cat_id, $action_items, $action_subcategories, $items_to_id, $subcategories_to_id);

					shop_plugins::plugin_do_ref('acp_category_delete', $errors);

					if (sizeof($errors))
					{
						break;
					}

					add_log('admin', 'LOG_SHOP_CATEGORY_DELETE', $row['cat_name']);
					trigger_error($user->lang['CATEGORY_DELETED'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id));

				break;

				case 'edit':
					$category_data = array(
						'cat_id'		=>	$cat_id
					);

				// No break here

				case 'add':

					$category_data += array(
						'parent_id'						=> request_var('category_parent_id', $this->parent_id),
						'cat_name'						=> utf8_normalize_nfc(request_var('cat_name', '', true)),
						'cat_desc'						=> utf8_normalize_nfc(request_var('cat_desc', '', true)),
						'cat_desc_bitfield'				=> '',
						'cat_desc_uid'					=> '',
						'cat_desc_options'				=> 7,
						'cat_rules'						=> utf8_normalize_nfc(request_var('rules', '', true)),
						'cat_rules_bitfield'			=> '',
						'cat_rules_uid'					=> '',
						'cat_rules_options'				=> 7,
					);

					// Get data for category rules if specified...
					if ($category_data['cat_rules'])
					{
						generate_text_for_storage($category_data['cat_rules'], $category_data['cat_rules_uid'], $category_data['cat_rules_bitfield'], $category_data['cat_rules_options'], request_var('rules_parse_bbcode', false), request_var('rules_parse_urls', false), request_var('rules_parse_smilies', false));
					}

					// Get data for category description if specified
					if ($category_data['cat_desc'])
					{
						generate_text_for_storage($category_data['cat_desc'], $category_data['cat_desc_uid'], $category_data['cat_desc_bitfield'], $category_data['cat_desc_options'], request_var('desc_parse_bbcode', false), request_var('desc_parse_urls', false), request_var('desc_parse_smilies', false));
					}

					extract(shop_plugins::plugin_do('acp_category_add_edit', compact('action', 'category_data')));

					$errors = $this->update_category_data($category_data);

					if (!sizeof($errors))
					{
						$message = ($action == 'add') ? $user->lang['CATEGORY_CREATED'] : $user->lang['CATEGORY_UPDATED'];

						trigger_error($message . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id));
					}

				break;
			}
		}

		switch ($action)
		{
			case 'move_up':
			case 'move_down':

				if (!$cat_id)
				{
					trigger_error($user->lang['NO_CATEGORY'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
				}

				$sql = 'SELECT *
					FROM ' . SHOP_CATS_TABLE . "
					WHERE cat_id = $cat_id";
				$result = $db->sql_query($sql);
				$row = $db->sql_fetchrow($result);
				$db->sql_freeresult($result);

				if (!$row)
				{
					trigger_error($user->lang['NO_CATEGORY'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
				}

				$move_cat_name = $this->move_category_by($row, $action, 1);
			break;

			case 'add':
			case 'edit':
				// Show form to create/modify a category
				if ($action == 'edit')
				{
					$this->page_title = 'EDIT_CATEGORY';
					$row = $this->get_category_info($cat_id);

					if (!$update)
					{
						$category_data = $row;
					}
					else
					{
						$category_data['left_id'] = $row['left_id'];
						$category_data['right_id'] = $row['right_id'];
					}

					// Make sure no direct child categories are able to be selected as parents.
					$exclude_categories = array();
					foreach (shop::get_category_branch($cat_id, 'children') as $row)
					{
						$exclude_categories[] = $row['cat_id'];
					}

					$parents_list = shop::make_category_select($category_data['parent_id'], $exclude_categories);
				}
				else
				{
					$this->page_title = 'CREATE_CATEGORY';

					$cat_id = $this->parent_id;
					$parents_list = shop::make_category_select($this->parent_id);

					// Fill category data with default values
					if (!$update)
					{
						$category_data = array(
							'parent_id'				=> $this->parent_id,
							'cat_name'				=> utf8_normalize_nfc(request_var('cat_name', '', true)),
							'cat_desc'				=> '',
							'cat_rules'				=> '',
						);
					}
				}

				$rules_data = array(
					'text'			=> $category_data['cat_rules'],
					'allow_bbcode'	=> true,
					'allow_smilies'	=> true,
					'allow_urls'	=> true
				);

				$cat_desc_data = array(
					'text'			=> $category_data['cat_desc'],
					'allow_bbcode'	=> true,
					'allow_smilies'	=> true,
					'allow_urls'	=> true
				);

				$rules_preview = '';

				// Parse rules if specified
				if ($category_data['cat_rules'])
				{
					if (!isset($category_data['cat_rules_uid']))
					{
						// Before we are able to display the preview and plane text, we need to parse our request_var()'d value...
						$category_data['cat_rules_uid'] = '';
						$category_data['cat_rules_bitfield'] = '';
						$category_data['cat_rules_options'] = 0;

						generate_text_for_storage($category_data['cat_rules'], $category_data['cat_rules_uid'], $category_data['cat_rules_bitfield'], $category_data['cat_rules_options'], request_var('rules_allow_bbcode', false), request_var('rules_allow_urls', false), request_var('rules_allow_smilies', false));
					}

					// Generate preview content
					$rules_preview = generate_text_for_display($category_data['cat_rules'], $category_data['cat_rules_uid'], $category_data['cat_rules_bitfield'], $category_data['cat_rules_options']);

					// decode...
					$rules_data = generate_text_for_edit($category_data['cat_rules'], $category_data['cat_rules_uid'], $category_data['cat_rules_options']);
				}

				// Parse desciption if specified
				if ($category_data['cat_desc'])
				{
					if (!isset($category_data['cat_desc_uid']))
					{
						// Before we are able to display the preview and plane text, we need to parse our request_var()'d value...
						$category_data['cat_desc_uid'] = '';
						$category_data['cat_desc_bitfield'] = '';
						$category_data['cat_desc_options'] = 0;

						generate_text_for_storage($category_data['cat_desc'], $category_data['cat_desc_uid'], $category_data['cat_desc_bitfield'], $category_data['cat_desc_options'], request_var('desc_allow_bbcode', false), request_var('desc_allow_urls', false), request_var('desc_allow_smilies', false));
					}

					// decode...
					$cat_desc_data = generate_text_for_edit($category_data['cat_desc'], $category_data['cat_desc_uid'], $category_data['cat_desc_options']);
				}

				$sql = 'SELECT cat_id
					FROM ' . SHOP_CATS_TABLE . "
						WHERE cat_id <> $cat_id";
				$result = $db->sql_query($sql);

				if ($db->sql_fetchrow($result))
				{
					$template->assign_vars(array(
						'S_MOVE_CATEGORY_OPTIONS'		=> shop::make_category_select($category_data['parent_id'], $cat_id))
					);
				}
				$db->sql_freeresult($result);

				$template->assign_vars(array(
					'S_ADD_ACTION'				=> ($mode == 'add') ? true : false,
					'S_ADD_CATEGORY'			=> ($action == 'edit') ? false : true,
					'S_EDIT_CATEGORY'			=> ($action == 'edit') ? true : false,
					'S_ERROR'					=> (sizeof($errors)) ? true : false,
					'S_PARENT_ID'				=> $this->parent_id,
					'S_CATEGORY_PARENT_ID'		=> $category_data['parent_id'],
					'S_PARENT_OPTIONS'			=> $parents_list,

					'U_BACK'					=> $this->u_action . '&amp;parent_id=' . $this->parent_id,
					'U_EDIT_ACTION'				=> $this->u_action . "&amp;parent_id={$this->parent_id}&amp;action=$action&amp;c=$cat_id",

					'L_TITLE'					=> $user->lang[$this->page_title],
					'ERROR_MSG'					=> (sizeof($errors)) ? implode('<br />', $errors) : '',

					'CATEGORY_NAME'				=> $category_data['cat_name'],
					'RULES'						=> $category_data['cat_rules'],
					'RULES_PREVIEW'				=> $rules_preview,
					'RULES_PLAIN'				=> $rules_data['text'],
					'S_BBCODE_CHECKED'			=> ($rules_data['allow_bbcode']) ? true : false,
					'S_SMILIES_CHECKED'			=> ($rules_data['allow_smilies']) ? true : false,
					'S_URLS_CHECKED'			=> ($rules_data['allow_urls']) ? true : false,

					'CATEGORY_DESCRIPTION'		=> $cat_desc_data['text'],
					'S_DESC_BBCODE_CHECKED'		=> ($cat_desc_data['allow_bbcode']) ? true : false,
					'S_DESC_SMILIES_CHECKED'	=> ($cat_desc_data['allow_smilies']) ? true : false,
					'S_DESC_URLS_CHECKED'		=> ($cat_desc_data['allow_urls']) ? true : false,

					'S_CATEGORY_OPTIONS'		=> shop::make_category_select(($action == 'add') ? $category_data['parent_id'] : false, ($action == 'edit') ? $category_data['cat_id'] : false),
				));

				shop_plugins::plugin_do('acp_category_add_edit_initial');

				return;

			break;

			case 'delete':
				if (!$cat_id)
				{
					trigger_error($user->lang['NO_CATEGORY'] . adm_back_link($this->u_action . '&amp;parent_id=' . $this->parent_id), E_USER_WARNING);
				}

				$category_data = $this->get_category_info($cat_id);

				$subcategories_id = array();
				$subcategories = shop::get_category_branch($cat_id, 'children');

				foreach ($subcategories as $row)
				{
					$subcategories_id[] = $row['cat_id'];
				}

				$categories_list = shop::make_category_select($category_data['parent_id'], $subcategories_id);

				$sql = 'SELECT cat_id
					FROM ' . SHOP_CATS_TABLE . "
						WHERE cat_id <> $cat_id";
				$result = $db->sql_query($sql);

				if ($db->sql_fetchrow($result))
				{
					$template->assign_vars(array(
						'S_MOVE_CATEGORY_OPTIONS'		=> shop::make_category_select($category_data['parent_id'], $subcategories_id))
					);
				}
				$db->sql_freeresult($result);

				$parent_id = ($this->parent_id == $cat_id) ? 0 : $this->parent_id;

				$template->assign_vars(array(
					'S_DELETE_CATEGORY'		=> true,
					'U_ACTION'				=> $this->u_action . "&amp;parent_id={$parent_id}&amp;action=delete&amp;c=$cat_id",
					'U_BACK'				=> $this->u_action . '&amp;parent_id=' . $this->parent_id,

					'CATEGORY_NAME'			=> $category_data['cat_name'],
					'S_HAS_SUBCATEGORYS'	=> ($category_data['right_id'] - $category_data['left_id'] > 1) ? true : false,
					'S_CATEGORIES_LIST'		=> $categories_list,
					'S_ERROR'				=> (sizeof($errors)) ? true : false,
					'ERROR_MSG'				=> (sizeof($errors)) ? implode('<br />', $errors) : '')
				);

				return;
			break;
		}

		// Default management page
		if (!$this->parent_id)
		{
			$navigation = $user->lang['CATEGORY_INDEX'];
		}
		else
		{
			$navigation = '<a href="' . $this->u_action . '">' . $user->lang['CATEGORY_INDEX'] . '</a>';

			$category_nav = shop::get_category_branch($this->parent_id, 'parents', 'descending');
			foreach ($category_nav as $row)
			{
				if ($row['cat_id'] == $this->parent_id)
				{
					$navigation .= ' -&gt; ' . $row['cat_name'];
				}
				else
				{
					$navigation .= ' -&gt; <a href="' . $this->u_action . '&amp;parent_id=' . $row['cat_id'] . '">' . $row['cat_name'] . '</a>';
				}
			}
		}

		// Jumpbox
		$category_box = shop::make_category_select($this->parent_id);

		$sql = 'SELECT *
			FROM ' . SHOP_CATS_TABLE . "
			WHERE parent_id = $this->parent_id
			ORDER BY left_id";
		$result = $db->sql_query($sql);

		if ($row = $db->sql_fetchrow($result))
		{
			do
			{
				$url = $this->u_action . "&amp;parent_id=$this->parent_id&amp;c={$row['cat_id']}";

				$category_title = $row['cat_name'];

				$template->assign_block_vars('categories', array(
					'CATEGORY_NAME'			=> $row['cat_name'],
					'CATEGORY_DESCRIPTION'	=> generate_text_for_display($row['cat_desc'], $row['cat_desc_uid'], $row['cat_desc_bitfield'], $row['cat_desc_options']),

					'U_CATEGORY'			=> $this->u_action . '&amp;parent_id=' . $row['cat_id'],
					'U_MOVE_UP'				=> $url . '&amp;action=move_up',
					'U_MOVE_DOWN'			=> $url . '&amp;action=move_down',
					'U_EDIT'				=> $url . '&amp;action=edit',
					'U_DELETE'				=> $url . '&amp;action=delete',
				));
			}
			while ($row = $db->sql_fetchrow($result));
		}
		else if ($this->parent_id)
		{
			$row = $this->get_category_info($this->parent_id);

			$url = $this->u_action . '&amp;parent_id=' . $this->parent_id . '&amp;c=' . $row['cat_id'];

			$template->assign_vars(array(
				'S_NO_CATEGORIES'		=> true,

				'U_EDIT'			=> $url . '&amp;action=edit',
				'U_DELETE'			=> $url . '&amp;action=delete',
			));
		}
		$db->sql_freeresult($result);

		$template->assign_vars(array(
			'ERROR_MSG'		=> (sizeof($errors)) ? implode('<br />', $errors) : '',
			'NAVIGATION'	=> $navigation,
			'CATEGORY_BOX'	=> $category_box,
			'U_SEL_ACTION'	=> $this->u_action,
			'U_ACTION'		=> $this->u_action . '&amp;parent_id=' . $this->parent_id,
		));
	}

	function plugins($id, $mode)
	{
		global $config, $db, $user, $auth, $template;

		if (shop_plugins::load_all_plugins() === false)
		{
			trigger_error('PLUGINS_DISABLED');
		}

		$submit = (isset($_POST['submit'])) ? true : false;
		$action = request_var('action', '');
		$action_to = request_var('name', '');

		$this->tpl_name = 'acp_shop_plugins';
		$this->page_title = 'ACP_SHOP_PLUGINS';

		$template->assign_vars(array(
			'U_ACTION'			=> $this->u_action,
		));

		switch ($action)
		{
			case 'activate' :
				shop_plugins::plugin_enable($action_to);
			break;
			case 'deactivate' :
				shop_plugins::plugin_disable($action_to);
			break;
			case 'install' :
				shop_plugins::plugin_install($action_to);
			break;
			case 'uninstall' :
				if (confirm_box(true))
				{
					shop_plugins::plugin_uninstall($action_to);
				}
				else
				{
					confirm_box(false, 'PLUGIN_UNINSTALL');
				}
			break;
			case 'update' :
				shop_plugins::plugin_update($action_to);
			break;
			case 'move_up' :
			case 'move_down' :
				shop_plugins::plugin_move($action_to, $action);

				// We need to do a redirect here because the plugins list is not shown correctly after one is moved...and I see no easy way to resync the list
				redirect($this->u_action);
			break;
		}

		$i = 0;
		$installed_plugins = array();
		foreach (shop_plugins::$available_plugins as $name => $data)
		{
			$i++;
			$installed = (array_key_exists($name, shop_plugins::$plugins)) ? true : false;
			$active = ($installed && shop_plugins::$plugins[$name]['plugin_enabled']) ? true : false;

			$s_actions = array();
			if ($installed)
			{
				if ($active)
				{
					$s_actions[] = '<a href="' . $this->u_action . "&amp;action=deactivate&amp;name=" . $name . '">' . $user->lang['PLUGIN_DEACTIVATE'] . '</a>';
					$s_actions[] = '<a href="' . $this->u_action . "&amp;action=uninstall&amp;name=" . $name . '">' . $user->lang['PLUGIN_UNINSTALL'] . '</a>';
				}
				else
				{
					$s_actions[] = '<a href="' . $this->u_action . "&amp;action=activate&amp;name=" . $name . '">' . $user->lang['PLUGIN_ACTIVATE'] . '</a>';
					$s_actions[] = '<a href="' . $this->u_action . "&amp;action=uninstall&amp;name=" . $name . '">' . $user->lang['PLUGIN_UNINSTALL'] . '</a>';
				}

				if ($i > 1)
				{
					$s_actions[] = '<a href="' . $this->u_action . "&amp;action=move_up&amp;name=" . $name . '">' . $user->lang['MOVE_UP'] . '</a>';
				}
				if ($i != sizeof(shop_plugins::$plugins))
				{
					$s_actions[] = '<a href="' . $this->u_action . "&amp;action=move_down&amp;name=" . $name . '">' . $user->lang['MOVE_DOWN'] . '</a>';
				}

				if ($data['plugin_version'] != shop_plugins::$plugins[$name]['plugin_version'])
				{
					$version = array('files' => explode('.', $data['plugin_version']), 'db' => explode('.', shop_plugins::$plugins[$name]['plugin_version']));

					$i = 0;
					$newer_files = false;
					foreach ($version['files'] as $v)
					{
						if ($v > $version['db'][$i])
						{
							$newer_files = true;
							break;
						}
						else if ($v < $version['db'][$i])
						{
							break;
						}
						$i++;
					}
					if ($newer_files)
					{
						$s_actions[] = '<a href="' . $this->u_action . "&amp;action=update&amp;name=" . $name . '">' . $user->lang['PLUGIN_UPDATE'] . '</a>';
					}
				}
			}
			else
			{
				$s_actions[] = '<a href="' . $this->u_action . "&amp;action=install&amp;name=" . $name . '">' . $user->lang['PLUGIN_INSTALL'] . '</a>';
			}

			if ($installed)
			{
				$installed_plugins[$name] = array(
					'NAME'				=> (isset($data['plugin_title'])) ? $data['plugin_title'] : $name,
					'DESCRIPTION'		=> (isset($data['plugin_description'])) ? $data['plugin_description'] : '',
					'S_ACTIONS'			=> implode(' | ', $s_actions),
					'COPYRIGHT'			=> (isset($data['plugin_copyright'])) ? $data['plugin_copyright'] : '',
					'DATABASE_VERSION'	=> ($installed) ? shop_plugins::$plugins[$name]['plugin_version'] : false,
					'FILES_VERSION'		=> (isset($data['plugin_version'])) ? $data['plugin_version'] : '',
				);
			}
			else
			{
				$template->assign_block_vars('uninstalled', array(
					'NAME'				=> (isset($data['plugin_title'])) ? $data['plugin_title'] : $name,
					'DESCRIPTION'		=> (isset($data['plugin_description'])) ? $data['plugin_description'] : '',
					'S_ACTIONS'			=> implode(' | ', $s_actions),
					'COPYRIGHT'			=> (isset($data['plugin_copyright'])) ? $data['plugin_copyright'] : '',
					'DATABASE_VERSION'	=> ($installed) ? shop_plugins::$plugins[$name]['plugin_version'] : false,
					'FILES_VERSION'		=> (isset($data['plugin_version'])) ? $data['plugin_version'] : '',
				));
			}
		}

		foreach (shop_plugins::$plugins as $name => $row)
		{
			$template->assign_block_vars('installed', $installed_plugins[$name]);
		}
	}

	/**
	* Get category details
	*/
	function get_category_info($cat_id)
	{
		global $db;

		$sql = 'SELECT *
			FROM ' . SHOP_CATS_TABLE . "
			WHERE cat_id = $cat_id";
		$result = $db->sql_query($sql);
		$row = $db->sql_fetchrow($result);
		$db->sql_freeresult($result);

		if (!$row)
		{
			trigger_error("Category #$cat_id does not exist", E_USER_ERROR);
		}

		return $row;
	}

	/**
	* Update category data
	*/
	function update_category_data(&$category_data)
	{
		global $db, $user;

		$errors = array();

		if (!$category_data['cat_name'])
		{
			$errors[] = $user->lang['CATEGORY_NAME_EMPTY'];
		}

		// Unset data that are not database fields
		$category_data_sql = $category_data;

		// What are we going to do tonight Brain? The same thing we do everynight,
		// try to take over the world ... or decide whether to continue update
		// and if so, whether it's a new category/cat/link or an existing one
		if (sizeof($errors))
		{
			return $errors;
		}

		if (!isset($category_data_sql['cat_id']))
		{
			// no cat_id means we're creating a new category
			if ($category_data_sql['parent_id'])
			{
				$sql = 'SELECT left_id, right_id
					FROM ' . SHOP_CATS_TABLE . '
						WHERE cat_id = ' . $category_data_sql['parent_id'];
				$result = $db->sql_query($sql);
				$row = $db->sql_fetchrow($result);
				$db->sql_freeresult($result);

				if (!$row)
				{
					trigger_error($user->lang['PARENT_NOT_EXIST'] . adm_back_link($this->u_action . '&amp;' . $this->parent_id), E_USER_WARNING);
				}

				$sql = 'UPDATE ' . SHOP_CATS_TABLE . '
					SET left_id = left_id + 2, right_id = right_id + 2
					WHERE left_id > ' . $row['right_id'];
				$db->sql_query($sql);

				$sql = 'UPDATE ' . SHOP_CATS_TABLE . '
					SET right_id = right_id + 2
					WHERE ' . $row['left_id'] . ' BETWEEN left_id AND right_id';
				$db->sql_query($sql);

				$category_data_sql['left_id'] = $row['right_id'];
				$category_data_sql['right_id'] = $row['right_id'] + 1;
			}
			else
			{
				$sql = 'SELECT MAX(right_id) AS right_id
					FROM ' . SHOP_CATS_TABLE;
				$result = $db->sql_query($sql);
				$row = $db->sql_fetchrow($result);
				$db->sql_freeresult($result);

				$category_data_sql['left_id'] = $row['right_id'] + 1;
				$category_data_sql['right_id'] = $row['right_id'] + 2;
			}

			$sql = 'INSERT INTO ' . SHOP_CATS_TABLE . ' ' . $db->sql_build_array('INSERT', $category_data_sql);
			$db->sql_query($sql);

			$category_data['cat_id'] = $db->sql_nextid();

			add_log('admin', 'LOG_SHOP_CATEGORY_ADD', $category_data['cat_name']);
		}
		else
		{
			$row = $this->get_category_info($category_data_sql['cat_id']);

			if (sizeof($errors))
			{
				return $errors;
			}

			if ($row['parent_id'] != $category_data_sql['parent_id'])
			{
				$errors = $this->move_category($category_data_sql['cat_id'], $category_data_sql['parent_id']);
			}

			if (sizeof($errors))
			{
				return $errors;
			}

			unset($category_data_sql['type_action']);

			// Setting the category id to the category id is not really received well by some dbs. ;)
			$cat_id = $category_data_sql['cat_id'];
			unset($category_data_sql['cat_id']);

			$sql = 'UPDATE ' . SHOP_CATS_TABLE . '
				SET ' . $db->sql_build_array('UPDATE', $category_data_sql) . '
				WHERE cat_id = ' . $cat_id;
			$db->sql_query($sql);

			// Add it back
			$category_data['cat_id'] = $cat_id;

			add_log('admin', 'LOG_SHOP_CATEGORY_EDIT', $category_data['cat_name']);
		}

		return $errors;
	}

	/**
	* Move category
	*/
	function move_category($from_id, $to_id)
	{
		global $db, $user;

		$to_data = $moved_ids = $errors = array();

		// Check if we want to move to a parent with link type
		if ($to_id > 0)
		{
			$to_data = $this->get_category_info($to_id);
		}

		$moved_categories = shop::get_category_branch($from_id, 'children', 'descending');
		$from_data = $moved_categories[0];
		$diff = sizeof($moved_categories) * 2;

		$moved_ids = array();
		for ($i = 0; $i < sizeof($moved_categories); ++$i)
		{
			$moved_ids[] = $moved_categories[$i]['cat_id'];
		}

		// Resync parents
		$sql = 'UPDATE ' . SHOP_CATS_TABLE . "
			SET right_id = right_id - $diff
			WHERE left_id < " . $from_data['right_id'] . "
				AND right_id > " . $from_data['right_id'];
		$db->sql_query($sql);

		// Resync righthand side of tree
		$sql = 'UPDATE ' . SHOP_CATS_TABLE . "
			SET left_id = left_id - $diff, right_id = right_id - $diff
			WHERE left_id > " . $from_data['right_id'];
		$db->sql_query($sql);

		if ($to_id > 0)
		{
			// Retrieve $to_data again, it may have been changed...
			$to_data = $this->get_category_info($to_id);

			// Resync new parents
			$sql = 'UPDATE ' . SHOP_CATS_TABLE . "
				SET right_id = right_id + $diff
				WHERE " . $to_data['right_id'] . ' BETWEEN left_id AND right_id
					AND ' . $db->sql_in_set('cat_id', $moved_ids, true);
			$db->sql_query($sql);

			// Resync the righthand side of the tree
			$sql = 'UPDATE ' . SHOP_CATS_TABLE . "
				SET left_id = left_id + $diff, right_id = right_id + $diff
				WHERE left_id > " . $to_data['right_id'] . '
					AND ' . $db->sql_in_set('cat_id', $moved_ids, true);
			$db->sql_query($sql);

			// Resync moved branch
			$to_data['right_id'] += $diff;

			if ($to_data['right_id'] > $from_data['right_id'])
			{
				$diff = '+ ' . ($to_data['right_id'] - $from_data['right_id'] - 1);
			}
			else
			{
				$diff = '- ' . abs($to_data['right_id'] - $from_data['right_id'] - 1);
			}
		}
		else
		{
			$sql = 'SELECT MAX(right_id) AS right_id
				FROM ' . SHOP_CATS_TABLE . '
				WHERE ' . $db->sql_in_set('cat_id', $moved_ids, true);
			$result = $db->sql_query($sql);
			$row = $db->sql_fetchrow($result);
			$db->sql_freeresult($result);

			$diff = '+ ' . ($row['right_id'] - $from_data['left_id'] + 1);
		}

		$sql = 'UPDATE ' . SHOP_CATS_TABLE . "
			SET left_id = left_id $diff, right_id = right_id $diff
			WHERE " . $db->sql_in_set('cat_id', $moved_ids);
		$db->sql_query($sql);

		return $errors;
	}

	/**
	* Move category content from one to another category
	*/
	function move_category_content($from_id, $to_id, $sync = true)
	{
		global $db;

		$sql = 'SELECT count(item_id) AS total FROM ' . SHOP_ITEMS_IN_CATS_TABLE . '
			WHERE cat_id = ' . $from_id;
		$result = $db->sql_query($sql);
		$row = $db->sql_fetchrow($result);
		if ($row !== false)
		{
			$sql = 'UPDATE ' . SHOP_CATS_TABLE . '
				SET item_count = item_count + ' . $row['total'] . '
					WHERE cat_id = \'' . $to_id . '\'';
			$db->sql_query($sql);
		}

		$sql = 'UPDATE ' . SHOP_CATS_TABLE . "
			SET cat_id = '$to_id'
			WHERE cat_id = '$from_id'";
		$db->sql_query($sql);

		return array();
	}

	/**
	* Delete category content
	*/
	function delete_category_content($cat_id)
	{
		global $db;

		$sql = 'DELETE FROM ' . SHOP_ITEMS_IN_CATS_TABLE . "
			WHERE cat_id = $cat_id";
		$db->sql_query($sql);

		return array();
	}

	/**
	* Remove complete category
	*/
	function delete_category($cat_id, $action_items = 'delete', $action_subcategories = 'delete', $items_to_id = 0, $subcategories_to_id = 0)
	{
		global $db, $user;

		$category_data = $this->get_category_info($cat_id);

		$errors = array();
		$log_action_posts = $log_action_categories = $posts_to_name = $subcategories_to_name = '';
		$cat_ids = array($cat_id);

		if (sizeof($errors))
		{
			return $errors;
		}

		if ($action_items == 'delete')
		{
			$errors = array_merge($errors, $this->delete_category_content($cat_id));
		}
		else if ($action_items == 'move')
		{
			if (!$items_to_id)
			{
				$errors[] = $user->lang['NO_DESTINATION_CATEGORY'];
			}
			else
			{
				$sql = 'SELECT cat_name
					FROM ' . SHOP_CATS_TABLE . '
					WHERE cat_id = ' . $item3s_to_id;
				$result = $db->sql_query($sql);
				$row = $db->sql_fetchrow($result);
				$db->sql_freeresult($result);

				if (!$row)
				{
					$errors[] = $user->lang['NO_CATEGORY'];
				}
				else
				{
					$items_to_name = $row['cat_name'];
					$errors = array_merge($errors, $this->move_category_content($cat_id, $items_to_id));
				}
			}
		}

		if (sizeof($errors))
		{
			return $errors;
		}

		if ($action_subcategories == 'delete')
		{
			$rows = shop::get_category_branch($cat_id, 'children', 'descending', false);

			foreach ($rows as $row)
			{
				$cat_ids[] = $row['cat_id'];
				$errors = array_merge($errors, $this->delete_category_content($row['cat_id']));
			}

			if (sizeof($errors))
			{
				return $errors;
			}

			$diff = sizeof($cat_ids) * 2;

			$sql = 'DELETE FROM ' . SHOP_CATS_TABLE . '
				WHERE ' . $db->sql_in_set('cat_id', $cat_ids);
			$db->sql_query($sql);
		}
		else if ($action_subcategories == 'move')
		{
			if (!$subcategories_to_id)
			{
				$errors[] = $user->lang['NO_DESTINATION_FORUM'];
			}
			else
			{
				$log_action_categories = 'MOVE_CATEGORIES';

				$sql = 'SELECT catname
					FROM ' . SHOP_CATS_TABLE . '
					WHERE cat_id = ' . $subcategories_to_id;
				$result = $db->sql_query($sql);
				$row = $db->sql_fetchrow($result);
				$db->sql_freeresult($result);

				if (!$row)
				{
					$errors[] = $user->lang['NO_CATEGORY'];
				}
				else
				{
					$subcategories_to_name = $row['cat_name'];

					$sql = 'SELECT cat_id
						FROM ' . SHOP_CATS_TABLE . "
						WHERE parent_id = $cat_id";
					$result = $db->sql_query($sql);

					while ($row = $db->sql_fetchrow($result))
					{
						$this->move_category($row['cat_id'], $subcategories_to_id);
					}
					$db->sql_freeresult($result);

					// Grab new category data for correct tree updating later
					$category_data = $this->get_category_info($cat_id);

					$sql = 'UPDATE ' . SHOP_CATS_TABLE . "
						SET parent_id = $subcategories_to_id
						WHERE parent_id = $cat_id";
					$db->sql_query($sql);

					$diff = 2;
					$sql = 'DELETE FROM ' . SHOP_CATS_TABLE . "
						WHERE cat_id = $cat_id";
					$db->sql_query($sql);
				}
			}

			if (sizeof($errors))
			{
				return $errors;
			}
		}
		else
		{
			$diff = 2;
			$sql = 'DELETE FROM ' . SHOP_CATS_TABLE . "
				WHERE cat_id = $cat_id";
			$db->sql_query($sql);
		}

		// Resync tree
		$sql = 'UPDATE ' . SHOP_CATS_TABLE . "
			SET right_id = right_id - $diff
			WHERE left_id < {$category_data['right_id']} AND right_id > {$category_data['right_id']}";
		$db->sql_query($sql);

		$sql = 'UPDATE ' . SHOP_CATS_TABLE . "
			SET left_id = left_id - $diff, right_id = right_id - $diff
			WHERE left_id > {$category_data['right_id']}";
		$db->sql_query($sql);

		add_log('admin', 'LOG_CATEGORY_DELETE', $category_data['cat_name']);

		return $errors;
	}

	/**
	* Move category position by $steps up/down
	*/
	function move_category_by($category_row, $action = 'move_up', $steps = 1)
	{
		global $db;

		/**
		* Fetch all the siblings between the module's current spot
		* and where we want to move it to. If there are less than $steps
		* siblings between the current spot and the target then the
		* module will move as far as possible
		*/
		$sql = 'SELECT cat_id, cat_name, left_id, right_id
			FROM ' . SHOP_CATS_TABLE . "
			WHERE parent_id = {$category_row['parent_id']}
				AND " . (($action == 'move_up') ? "right_id < {$category_row['right_id']} ORDER BY right_id DESC" : "left_id > {$category_row['left_id']} ORDER BY left_id ASC");
		$result = $db->sql_query_limit($sql, $steps);

		$target = array();
		while ($row = $db->sql_fetchrow($result))
		{
			$target = $row;
		}
		$db->sql_freeresult($result);

		if (!sizeof($target))
		{
			// The category is already on top or bottom
			return false;
		}

		/**
		* $left_id and $right_id define the scope of the nodes that are affected by the move.
		* $diff_up and $diff_down are the values to substract or add to each node's left_id
		* and right_id in order to move them up or down.
		* $move_up_left and $move_up_right define the scope of the nodes that are moving
		* up. Other nodes in the scope of ($left_id, $right_id) are considered to move down.
		*/
		if ($action == 'move_up')
		{
			$left_id = $target['left_id'];
			$right_id = $category_row['right_id'];

			$diff_up = $category_row['left_id'] - $target['left_id'];
			$diff_down = $category_row['right_id'] + 1 - $category_row['left_id'];

			$move_up_left = $category_row['left_id'];
			$move_up_right = $category_row['right_id'];
		}
		else
		{
			$left_id = $category_row['left_id'];
			$right_id = $target['right_id'];

			$diff_up = $category_row['right_id'] + 1 - $category_row['left_id'];
			$diff_down = $target['right_id'] - $category_row['right_id'];

			$move_up_left = $category_row['right_id'] + 1;
			$move_up_right = $target['right_id'];
		}

		// Now do the dirty job
		$sql = 'UPDATE ' . SHOP_CATS_TABLE . "
			SET left_id = left_id + CASE
				WHEN left_id BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up}
				ELSE {$diff_down}
			END,
			right_id = right_id + CASE
				WHEN right_id BETWEEN {$move_up_left} AND {$move_up_right} THEN -{$diff_up}
				ELSE {$diff_down}
			END
			WHERE
				left_id BETWEEN {$left_id} AND {$right_id}
				AND right_id BETWEEN {$left_id} AND {$right_id}";
		$db->sql_query($sql);

		return $target['cat_name'];
	}
}
?>